home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 16
/
Aminet 16 (1996)(GTI - Schatztruhe)[!][Dec 1996].iso
/
Aminet
/
comm
/
term
/
term_source.lha
/
Extras
/
Source
/
term-source.lha
/
Locale.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-10-20
|
18KB
|
832 lines
/*
** Locale.c
**
** Localization support routines
**
** Copyright © 1990-1996 by Olaf `Olsen' Barthel
** All Rights Reserved
**
** :ts=4
*/
#ifndef _GLOBAL_H
#include "Global.h"
#endif
/* LocaleOpen(STRPTR CatalogName,STRPTR BuiltIn):
*
* Open string translation tables.
*/
VOID
LocaleOpen(STRPTR CatalogName,STRPTR BuiltIn,LONG Version)
{
DecimalPoint = ".";
strcpy(ConvNumber,"%ld");
strcpy(ConvNumber10,"%10ld");
if(LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38))
{
if(LocaleBase->lb_SysPatches)
{
strcpy(ConvNumber,"%lD");
strcpy(ConvNumber10,"%10lD");
if(Catalog = OpenCatalog(NULL,CatalogName,
OC_BuiltInLanguage, BuiltIn,
OC_BuiltInCodeSet, 0,
Language[0] ? OC_Language : TAG_IGNORE,Language,
TAG_DONE))
{
BOOL TooOld = FALSE;
/* Don't load an outdated catalog file */
if(Catalog->cat_Version < Version)
TooOld = TRUE;
else
{
if(strcmp(GetCatalogStr(Catalog,MSG_OFFSET_TEST1_TXT,""),"v4.0"))
TooOld = TRUE;
}
if(TooOld)
{
BOOL IntuitionOpen;
if(IntuitionBase)
IntuitionOpen = TRUE;
else
{
IntuitionOpen = FALSE;
IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37);
}
if(IntuitionBase)
ShowRequest(NULL,"The catalog file is too old to be used\nwith this `term' revision.","Continue");
if(!IntuitionOpen)
{
CloseLibrary((struct Library *)IntuitionBase);
IntuitionBase = NULL;
}
CloseCatalog(Catalog);
Catalog = NULL;
}
}
Locale = OpenLocale(NULL);
DecimalPoint = Locale->loc_DecimalPoint;
}
else
{
CloseLibrary((struct Library *)LocaleBase);
LocaleBase = NULL;
}
}
/* If we couldn't open locale.library or if the patches are
* not installed, and if we are running under Kickstart 2.04
* we'll change the number formatting codes in the built-in
* catalog strings.
*/
if(!LocaleBase && SysBase->LibNode.lib_Version == 37)
{
struct CatCompArrayType *Entry;
STRPTR String;
UBYTE c;
LONG i;
for(i = 0, Entry = AppStrings ; i < NumAppStrings ; i++, Entry++)
{
String = Entry->cca_Str;
while(c = *String++)
{
if(c == '%' && *String != '%')
{
STATIC BYTE Stops[256] =
{
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,1,0,1,0,0,1,0,0,0,0,0,0,0,
0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,1,0,1,0,0,1,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
while(c = *String)
{
if(!Stops[c])
String++;
else
{
if(c == 'D')
*String = 'd';
break;
}
}
if(!c)
break;
}
}
}
}
}
/* LocaleClose():
*
* Close the translation tables.
*/
VOID
LocaleClose()
{
if(LocaleBase)
{
CloseLocale(Locale);
Locale = NULL;
CloseCatalog(Catalog);
Catalog = NULL;
CloseLibrary((struct Library *)LocaleBase);
LocaleBase = NULL;
}
}
/* LanguageCheck():
*
* Checks to see if the currently selected language
* is english.
*/
VOID
LanguageCheck()
{
if(Locale && Catalog)
{
if(Locale->loc_LanguageName)
{
if(!Stricmp(Locale->loc_LanguageName,"english.language"))
English = TRUE;
else
English = FALSE;
}
else
English = FALSE;
}
else
English = TRUE;
}
/* SmallCurrency():
*
* Support function for the rates control panel, returns a formatted
* string to contain a string like "cents/unit".
*/
VOID
SmallCurrency(STRPTR Buffer,LONG BufferSize)
{
if(Locale)
LimitedSPrintf(BufferSize,Buffer,LocaleString(MSG_RATEPANEL_PAY_PER_UNIT_GAD),Locale->loc_MonSmallCS);
else
LimitedSPrintf(BufferSize,Buffer,LocaleString(MSG_RATEPANEL_PAY_PER_UNIT_GAD),"Pay");
}
/* InsertGrouping(STRPTR Buffer,STRPTR GroupData,STRPTR GroupSeparator):
*
* Tricky stuff, folks! This beauty will insert grouping characters
* into a readily-prepared string buffer filled with numeric
* contents. It takes the group separator tokens and group separator
* strings into account.
*/
VOID
InsertGrouping(STRPTR Buffer,STRPTR GroupData,STRPTR GroupSeparator)
{
UBYTE LocalBuffer[80]; /* Sufficient, but too large */
STRPTR Index;
LONG i,j,SeparatorSize;
LONG Count; /* How many characters per group */
BOOL RepeatGroupCount; /* Keep repeating group size until end */
RepeatGroupCount = FALSE;
/* Set up for the first group */
switch(*GroupData)
{
case 0: /* Repeat current grouping scheme until end */
case 255: /* No further grouping is to be performed */
Count = 0;
break;
default: /* Initial group size */
Count = *GroupData++;
break;
}
/* Check the size of the group separator string */
if((SeparatorSize = strlen(GroupSeparator) - 1) < 1)
Count = 0;
/* That where we'll start */
Index = LocalBuffer;
/* Build the string back to front, we will reverse it later */
for(i = strlen(Buffer) - 1, j = 1 ; i >= 0 ; i--, j++)
{
/* Pick up the next number character */
*Index++ = Buffer[i];
/* Are we to insert the grouping characters here? */
if(Count && j == Count)
{
LONG k;
/* Insert the grouping characters */
for(k = SeparatorSize ; k >= 0 ; k--)
*Index++ = GroupSeparator[k];
/* Reset the group size counter */
j = 0;
/* Pick up the next grouping token? */
if(!RepeatGroupCount)
{
/* Ok, what kind of token is it? */
switch(*GroupData)
{
case 0: /* Repeat current grouping scheme */
RepeatGroupCount = TRUE;
break;
case 255: /* Perform no further grouping */
Count = 0;
break;
default: /* New group size */
Count = *GroupData++;
break;
}
}
}
}
/* Look how long the resulting string is */
j = ((LONG)Index - (LONG)LocalBuffer) - 1;
/* Copy it back */
Index = Buffer;
/* Reverse the order of characters while copying */
for(i = j ; i >= 0 ; i--)
*Index++ = LocalBuffer[i];
/* Provide null-termination */
*Index = 0;
}
STATIC VOID
ConvertMonetaryQuantity(LONG Units,STRPTR Destination,LONG DestinationSize,BOOL UseCurrency)
{
UBYTE IntegerBuffer[80]; /* Sufficient, but too large */
STRPTR SignText, /* Signed/unsigned quantity text */
SpaceText, /* Currency/number separation */
Currency; /* The name of the currency */
LONG SpaceSep, /* A space separates currency and quantity? */
SignPos, /* Where to place the sign text */
CSPos; /* Where to place the currency text */
LONG Sign; /* Negative or positive quantity? */
/* Negative quantity? */
if(Units < 0)
{
Sign = -1;
Units = -Units;
}
else
Sign = 1;
/* Does this currency sport a fractional smaller currency? */
if(Locale->loc_MonFracDigits)
{
UBYTE NumberBuffer[10],
FractionBuffer[40];
LONG Integer,
Fraction,
Scale;
LONG i;
/* Prepare the formatting string */
LimitedSPrintf(sizeof(NumberBuffer),NumberBuffer,"%%0%ldld",Locale->loc_MonFracDigits);
/* Turn the number of fractional digits into a power of ten */
for(i = 0, Scale = 1 ; i < Locale->loc_MonFracDigits ; i++)
Scale *= 10;
/* Split the quantity in integer and fractional part */
Integer = Units / Scale;
Fraction = Units % Scale;
/* Build the integer text */
LimitedSPrintf(sizeof(IntegerBuffer),IntegerBuffer,"%ld",Integer);
InsertGrouping(IntegerBuffer,Locale->loc_MonGrouping,Locale->loc_MonGroupSeparator);
/* Build the fractional text */
LimitedSPrintf(sizeof(FractionBuffer),FractionBuffer,NumberBuffer,Fraction);
InsertGrouping(FractionBuffer,Locale->loc_MonFracGrouping,Locale->loc_MonFracGroupSeparator);
/* Add the monetary decimal point */
LimitedStrcat(sizeof(IntegerBuffer),IntegerBuffer,Locale->loc_MonDecimalPoint);
/* Add the fractional part */
LimitedStrcat(sizeof(IntegerBuffer),IntegerBuffer,FractionBuffer);
}
else
{
/* Build the integer text */
LimitedSPrintf(sizeof(IntegerBuffer),IntegerBuffer,"%ld",Units);
InsertGrouping(IntegerBuffer,Locale->loc_MonGrouping,Locale->loc_MonGroupSeparator);
}
/* Pick up the appropriate formatting parameters */
if(Sign < 0)
{
SignText = Locale->loc_MonNegativeSign;
SpaceSep = Locale->loc_MonNegativeSpaceSep;
SignPos = Locale->loc_MonNegativeSignPos;
CSPos = Locale->loc_MonNegativeCSPos;
}
else
{
SignText = Locale->loc_MonPositiveSign;
SpaceSep = Locale->loc_MonPositiveSpaceSep;
SignPos = Locale->loc_MonPositiveSignPos;
CSPos = Locale->loc_MonPositiveCSPos;
}
/* Are we to use the currency symbol? */
if(UseCurrency)
{
/* Pick up the currency text */
Currency = Locale->loc_MonCS;
/* Take care of the separation information */
if(SpaceSep == SS_NOSPACE)
SpaceText = "";
else
SpaceText = " ";
}
else
Currency = SpaceText = "";
/* Now merge all the information into one single string */
if(CSPos == CSP_PRECEDES)
{
switch(SignPos)
{
case SP_PARENS:
/* (Currency <Space> Sign Value) */
LimitedSPrintf(DestinationSize,Destination,"(%s%s%s%s)",Currency,SpaceText,SignText,IntegerBuffer);
break;
case SP_PREC_ALL:
/* Sign Currency <Space> Value */
LimitedSPrintf(DestinationSize,Destination,"%s%s%s%s",SignText,Currency,SpaceText,IntegerBuffer);
break;
case SP_SUCC_ALL:
/* Currency <Space> Value Sign */
LimitedSPrintf(DestinationSize,Destination,"%s%s%s%s",Currency,SpaceText,IntegerBuffer,SignText);
break;
case SP_PREC_CURR:
/* Sign Currency <Space> Value */
LimitedSPrintf(DestinationSize,Destination,"%s%s%s%s",SignText,Currency,SpaceText,IntegerBuffer);
break;
case SP_SUCC_CURR:
/* Currency Sign <Space> Value */
LimitedSPrintf(DestinationSize,Destination,"%s%s%s%s",Currency,SignText,SpaceText,IntegerBuffer);
break;
}
}
else
{
switch(SignPos)
{
case SP_PARENS:
/* (Sign Value <Space> Currency) */
LimitedSPrintf(DestinationSize,Destination,"(%s%s%s%s)",SignText,IntegerBuffer,SpaceText,Currency);
break;
case SP_PREC_ALL:
/* Sign Value <Space> Currency */
LimitedSPrintf(DestinationSize,Destination,"%s%s%s%s",SignText,IntegerBuffer,SpaceText,Currency);
break;
case SP_SUCC_ALL:
/* Value <Space> Currency Sign */
LimitedSPrintf(DestinationSize,Destination,"%s%s%s%s",IntegerBuffer,SpaceText,Currency,SignText);
break;
case SP_PREC_CURR:
/* Value <Space> Sign Currency */
LimitedSPrintf(DestinationSize,Destination,"%s%s%s%s",IntegerBuffer,SpaceText,SignText,Currency);
break;
case SP_SUCC_CURR:
/* Value <Space> Currency Sign */
LimitedSPrintf(DestinationSize,Destination,"%s%s%s%s",IntegerBuffer,SpaceText,Currency,SignText);
break;
}
}
}
/* CreateSum(LONG Quantity):
*
* Create a string containing a monetary quantity formatted
* according to the current locale rules.
*/
VOID
CreateSum(LONG Quantity,BOOL UseCurrency,STRPTR Buffer,LONG BufferSize)
{
if(Locale)
ConvertMonetaryQuantity(Quantity,Buffer,BufferSize,UseCurrency);
else
LimitedSPrintf(BufferSize,Buffer,"%ld.%02ld",Quantity / 100,Quantity % 100);
}
/* LocalizeString(STRPTR *Strings,LONG From,LONG To):
*
* Localize an array of strings.
*/
VOID
LocalizeString(STRPTR *Strings,LONG From,LONG To)
{
if(!Strings[0])
{
LONG i,j;
for(i = From, j = 0 ; i <= To ; i++, j++)
Strings[j] = LocaleString(i);
}
}
/* LocalizeStringTable(STRPTR *Strings,LONG *Table)
*
* Localize an array of strings by table.
*/
VOID
LocalizeStringTable(STRPTR *Strings,LONG *Table)
{
while(*Table != -1)
*Strings++ = LocaleString(*Table++);
*Strings = NULL;
}
/* LocaleString(ULONG ID):
*
* Obtain a string from the translation pool.
*/
STRPTR
LocaleString(ULONG ID)
{
STRPTR Builtin;
if(ID < NumAppStrings && AppStrings[ID].cca_ID == ID)
Builtin = AppStrings[ID].cca_Str;
else
{
LONG Left,Mid,Right;
/* Binary search, note: can be applied here */
/* only because the catalog entries are */
/* stored in ascending ID order. But actually, */
/* this piece of code should never get called. */
Left = 0;
Right = NumAppStrings - 1;
do
{
Mid = (Left + Right) / 2;
if(ID < AppStrings[Mid].cca_ID)
Right = Mid - 1;
else
Left = Mid + 1;
}
while(ID != AppStrings[Mid].cca_ID && Left <= Right);
if(ID == AppStrings[Mid].cca_ID)
Builtin = AppStrings[Mid].cca_Str;
else
Builtin = "";
}
if(Catalog)
{
STRPTR String = GetCatalogStr(Catalog,ID,Builtin);
if(String[0])
return(String);
}
return(Builtin);
}
STRPTR SAVE_DS ASM
LocaleHookFunc(REG(a0) struct Hook *UnusedHook,REG(a2) APTR Unused,REG(a1) LONG ID)
{
return(LocaleString(ID));
}
STATIC LONG SAVE_DS ASM
FormatDateHookFunc(REG(a0) struct Hook *Hook,REG(a2) APTR Unused,REG(a1) UBYTE Char)
{
struct FormatContext *Context = Hook->h_Data;
if(Context->Size > 0)
{
*Context->Index++ = Char;
if(--Context->Size == 1)
{
*Context->Index = 0;
Context->Size = 0;
}
}
return(TRUE);
}
/* FormatStamp():
*
* Convert a date stamp into human readable
* form by taking the current locale parameters
* into account.
*/
BOOL
FormatStamp(struct DateStamp *Stamp,STRPTR BothBuffer,LONG BothBufferSize,BOOL SubstituteDay)
{
struct DateStamp Now;
/* If no time stamp given, do with current time */
if(!Stamp)
CurrentTimeToStamp(Stamp = &Now);
/* Is the current locale available? */
if(Locale)
{
struct FormatContext Context;
struct Hook LocalHook;
InitHook(&LocalHook,(HOOKFUNC)FormatDateHookFunc,&Context);
/* Combine date and time text? */
if(!SubstituteDay)
{
Context.Index = BothBuffer;
Context.Size = BothBufferSize;
FormatDate(Locale,Locale->loc_DateTimeFormat,Stamp,&LocalHook);
StripSpaces(BothBuffer);
}
else
{
UBYTE DateBuffer[40],TimeBuffer[40];
/* Are we to substitute the current day with */
/* text such as today, yesterday, etc.? */
if(SubstituteDay)
{
struct DateStamp Today;
STRPTR String;
/* Get the current time */
CurrentTimeToStamp(&Today);
/* Does the date refer to yesterday? */
if(Stamp->ds_Days == Today.ds_Days - 1)
String = GetLocaleStr(Locale,YESTERDAYSTR);
else
{
/* Does the date refer to today? */
if(Stamp->ds_Days == Today.ds_Days)
String = GetLocaleStr(Locale,TODAYSTR);
else
{
/* Does the date refer to tomorrow? */
if(Stamp->ds_Days == Today.ds_Days + 1)
String = GetLocaleStr(Locale,TOMORROWSTR);
else
{
String = NULL;
SubstituteDay = FALSE;
}
}
}
if(String)
LimitedStrcpy(sizeof(DateBuffer),DateBuffer,String);
else
DateBuffer[0] = 0;
}
if(!SubstituteDay)
{
Context.Index = DateBuffer;
Context.Size = sizeof(DateBuffer);
FormatDate(Locale,Locale->loc_DateFormat,Stamp,&LocalHook);
}
StripSpaces(DateBuffer);
Context.Index = TimeBuffer;
Context.Size = sizeof(TimeBuffer);
FormatDate(Locale,Locale->loc_TimeFormat,Stamp,&LocalHook);
StripSpaces(TimeBuffer);
/* Combine date and time */
LimitedSPrintf(BothBufferSize,BothBuffer,"%s %s",DateBuffer,TimeBuffer);
}
}
else
{
UBYTE DateBuffer[40],TimeBuffer[40];
struct DateTime DateTime;
/* No locale, so we will use dos.library instead. */
CopyMem(Stamp,&DateTime.dat_Stamp,sizeof(struct DateStamp));
DateTime.dat_Format = FORMAT_DOS;
DateTime.dat_Flags = SubstituteDay ? DTF_SUBST : NULL;
DateTime.dat_StrDay = NULL;
DateTime.dat_StrDate = DateBuffer;
DateTime.dat_StrTime = TimeBuffer;
if(!DateToStr(&DateTime))
return(FALSE);
StripSpaces(DateBuffer);
StripSpaces(TimeBuffer);
/* Combine date and time */
LimitedSPrintf(BothBufferSize,BothBuffer,"%s %s",DateBuffer,TimeBuffer);
}
return(TRUE);
}
/* FormatTime(STRPTR Buffer,LONG Hours,LONG Minutes,LONG Seconds):
*
* Given hours, minutes and seconds, format this data into
* a human-readable string.
*/
VOID
FormatTime(STRPTR Buffer,LONG BufferSize,LONG Hours,LONG Minutes,LONG Seconds)
{
if(Locale)
{
struct Hook LocalHook;
struct FormatContext Context;
struct DateStamp Stamp;
Stamp.ds_Days = 0;
Stamp.ds_Minute = Hours * 60 + Minutes;
Stamp.ds_Tick = MAX(0,Seconds) * TICKS_PER_SECOND;
Context.Index = Buffer;
Context.Size = BufferSize;
InitHook(&LocalHook,(HOOKFUNC)FormatDateHookFunc,&Context);
if(Seconds < 0)
FormatDate(Locale,Locale->loc_ShortTimeFormat,&Stamp,&LocalHook);
else
FormatDate(Locale,Locale->loc_TimeFormat,&Stamp,&LocalHook);
}
else
{
if(Seconds < 0)
LimitedSPrintf(BufferSize,Buffer,"%02ld:%02ld",Hours,Minutes);
else
LimitedSPrintf(BufferSize,Buffer,"%02ld:%02ld:%02ld",Hours,Minutes,Seconds);
}
}
/* StandardShowTime(struct Gadget *SomeGadget,LONG Level):
*
* Callback routine to display some time level.
*/
STRPTR SAVE_DS STACKARGS
StandardShowTime(struct Gadget *UnusedGadget,LONG Seconds)
{
STATIC UBYTE Time[10];
STRPTR FormatString;
if(LocaleBase)
FormatString = "%2lD%s%02lD";
else
FormatString = "%2ld%s%02ld";
LimitedSPrintf(sizeof(Time),Time,FormatString,Seconds / 100,DecimalPoint,Seconds % 100);
return(Time);
}